﻿
Imports std
Imports osi.input
Imports osi.input.constants
Imports osi.input.constants.key_board

Public Class console_key_board_agent
    Inherits agent(Of console_key_board_agent_settings)
    Implements agent_t

    Public Sub New(Optional ByVal settings As console_key_board_agent_settings = Nothing)
        MyBase.New(settings)
    End Sub

    Private Shared Sub wrap(ByVal cs As vector(Of [case]), ByVal mask As UInt16, ByVal inner As void)
        cs.push_back(key_board.[case](action.down, mask))
        void_(inner)
        cs.push_back(key_board.[case](action.press, mask))
        cs.push_back(key_board.[case](action.up, mask))
    End Sub

    Private Shared Sub modifier_wrap(ByVal ki As ConsoleKeyInfo,
                                     ByVal modifier As ConsoleModifiers,
                                     ByVal mask As UInt16,
                                     ByVal cs As vector(Of [case]),
                                     ByVal inner As void)
        assert(Not inner Is Nothing)
        If ki.Modifiers() And modifier Then
            wrap(cs, mask, inner)
        Else
            inner()
        End If
    End Sub

    Protected Overrides Sub initial()
        MyBase.initial()
        Console.TreatControlCAsInput() = True
    End Sub

    Protected Overrides Function precondition() As Boolean
        Return Console.KeyAvailable()
    End Function

    Protected Overrides Function cases() As vector(Of [case])
        Dim cs As vector(Of [case]) = Nothing
        cs = New vector(Of [case])()
        Dim ki As ConsoleKeyInfo = Nothing
        ki = Console.ReadKey(True)
        Dim key As void =
            Sub()
                wrap(cs, ki.Key(), Nothing)
            End Sub
        Dim shift As void =
            Sub()
                modifier_wrap(ki, ConsoleModifiers.Shift, mask.shift, cs, key)
            End Sub
        Dim control As void =
            Sub()
                modifier_wrap(ki, ConsoleModifiers.Control, mask.control, cs, shift)
            End Sub
        modifier_wrap(ki, ConsoleModifiers.Alt, mask.alt, cs, control)
        Return cs
    End Function
End Class
